package com.hmy.finance.service.receipt.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hmy.ccp.common.dto.BaseDto;
import com.hmy.ccp.common.dto.ContextUserInfo;
import com.hmy.ccp.common.response.BasePageResponse;
import com.hmy.ccp.datapermission.aop.DataPermission;
import com.hmy.ccp.datapermission.aop.DataPermissionGroup;
import com.hmy.ccp.error.exception.HMYRuntimeException;
import com.hmy.ccp.starter.web.utils.UserContextUtil;
import com.hmy.finance.api.bo.core.request.enums.ReceiptOffsetBillStatusEnum;
import com.hmy.finance.api.bo.core.request.enums.ReceiptedTypeEnum;
import com.hmy.finance.api.bo.core.request.receiptOffset.*;
import com.hmy.finance.api.bo.core.response.customerBalance.CustomerBalanceAccountInfoResponse;
import com.hmy.finance.api.bo.core.response.customerContactorBalance.ContactorBalanceAccountInfoResponse;
import com.hmy.finance.api.bo.core.response.customerContactorBalance.CustomerContactorBalanceAccountInfoResponse;
import com.hmy.finance.api.bo.core.response.receiptOffset.*;
import com.hmy.finance.api.common.enums.receipt.AccountTradeBusinessTypeEnum;
import com.hmy.finance.api.enums.ReceiptOffsetApprovalNodeEnum;
import com.hmy.finance.common.constants.ReceiptOffsetConstant;
import com.hmy.finance.common.constants.ReceiptOffsetStatusConstant;
import com.hmy.finance.common.constants.RedisKeyConstant;
import com.hmy.finance.common.utils.CommonCodeGenerator;
import com.hmy.finance.dal.dos.receipt.ReceiptOffsetBillInfoDo;
import com.hmy.finance.dal.dos.receipt.ReceiptOffsetBillPageQueryDo;
import com.hmy.finance.dal.mapper.DeviceDailyBillMapper;
import com.hmy.finance.dal.mapper.DeviceRentalRecordMapper;
import com.hmy.finance.dal.mapper.ReceivableInventoryMapper;
import com.hmy.finance.dal.mapper.receipt.ReceiptContractApportionRecordMapper;
import com.hmy.finance.dal.mapper.receipt.ReceiptOffsetBillMapper;
import com.hmy.finance.dal.mapper.receipt.ReceiptVoucherMapper;
import com.hmy.finance.dal.po.ContractEarliestRentalPo;
import com.hmy.finance.dal.po.ReceivableInventoryPo;
import com.hmy.finance.dal.po.json.VoucherAttachmentsJson;
import com.hmy.finance.dal.po.receipt.ReceiptContractApportionRecordPo;
import com.hmy.finance.dal.po.receipt.ReceiptOffsetBillPageQueryPo;
import com.hmy.finance.dal.po.receipt.ReceiptOffsetBillPo;
import com.hmy.finance.dal.po.receipt.ReceiptVoucherPo;
import com.hmy.finance.dal.po.receipt.json.CustomerContactorIAccountInfoJson;
import com.hmy.finance.manager.workflow.FlowProcessClientManager;
import com.hmy.finance.manager.workflow.FlowTaskClientManager;
import com.hmy.finance.service.core.IReceivableInventoryService;
import com.hmy.finance.service.rdto.ContractTotalReceivableRdto;
import com.hmy.finance.service.receipt.*;
import com.hmy.finance.service.receipt.dto.contactorAccount.TransferDto;
import com.hmy.finance.service.receipt.dto.customerAccount.CustomerIncomeDto;
import com.hmy.finance.service.receipt.dto.offset.ManualOffsetDto;
import com.hmy.finance.service.receipt.dto.receiptOffset.*;
import com.hmy.finance.service.receipt.dto.*;
import com.hmy.finance.service.receipt.rdto.TradeRdto;
import com.hmy.finance.service.receipt.rdto.offset.ManualOffsetRdto;
import com.hmy.workflow.api.bo.request.process.StartProcessInstanceRequest;
import com.hmy.workflow.api.bo.request.task.ApprovalTaskRequest;
import com.hmy.workflow.api.bo.response.process.StartProcessInstanceResponse;

import com.hmy.workflow.api.bo.response.task.ApprovalTaskResponse;

import java.util.*;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.stream.Collectors;

/**
 * @author loqel
 * @description 针对表【receipt_offset_bill(收款核销申请单)】的数据库操作Service实现
 * @createDate 2024-04-11 11:33:19
 */
@Service
@Slf4j
@RefreshScope
public class ReceiptOffsetBillServiceImpl implements ReceiptOffsetBillService {

    @Value("${process.receiptOffsetBill.start}")
    private String startProcessId;

    @Resource
    private FlowProcessClientManager flowProcessClientManager;

    @Resource
    private CustomerBalanceAccountService customerBalanceAccountService;

    @Resource
    private CustomerContactorBalanceAccountService customerContactorBalanceAccountService;

    @Resource
    private IReceivableInventoryService receivableInventoryService;

    @Resource
    private IncomeExpensesService incomeExpensesService;

    @Resource
    private OffsetFeeBillService offsetFeeBillService;

    @Resource
    private IdentifierGenerator identifierGenerator;

    @Resource
    private CommonCodeGenerator commonCodeGenerator;

    @Resource
    private ReceiptOffsetBillMapper receiptOffsetBillMapper;

    @Resource
    private ReceiptContractApportionRecordMapper receiptContractApportionRecordMapper;

    @Resource
    private ReceiptVoucherMapper receiptVoucherMapper;

    @Resource
    private ReceivableInventoryMapper receivableInventoryMapper;

    @Resource
    private DeviceDailyBillMapper deviceDailyBillMapper;

    @Resource
    private DeviceRentalRecordMapper deviceRentalRecordMapper;

    @Resource
    private FlowTaskClientManager flowTaskClientManager;

    @Override
    @DataPermissionGroup(permissionSql = {@DataPermission(sql = "com.hmy.finance.dal.mapper.receipt.ReceiptOffsetBillMapper.selectRecordsCountByReceiptOffsetParams", tableAlias = "rob", userField = "sale_manager_id", deptField = "sale_manager_dept_id"), @DataPermission(sql = "com.hmy.finance.dal.mapper.receipt.ReceiptOffsetBillMapper.selectRecordsByReceiptOffsetParams", tableAlias = "rob", userField = "sale_manager_id", deptField = "sale_manager_dept_id")})
    public BasePageResponse<ReceiptOffsetBillResponse> queryReceiptOffsetBillPageInfosByBoss(ReceiptOffsetBillBossPageQueryRequest receiptOffsetBillBossPageQueryRequest) {
        log.info("queryReceiptOffsetBillPageInfosByBoss request:{}", JSONUtil.toJsonStr(receiptOffsetBillBossPageQueryRequest));
        ReceiptOffsetBillBossPageQueryDto receiptOffsetBillBossPageQueryDto = BeanUtil.copyProperties(receiptOffsetBillBossPageQueryRequest, ReceiptOffsetBillBossPageQueryDto.class);
        receiptOffsetBillBossPageQueryDto.mappingStatus2BillStatus();

        ReceiptOffsetBillPageQueryPo receiptOffsetBillPageQueryPo = new ReceiptOffsetBillPageQueryPo();
        bossPageInfosQueryWrapperPackager(receiptOffsetBillBossPageQueryDto, receiptOffsetBillPageQueryPo);
        Integer count = receiptOffsetBillMapper.selectRecordsCountByReceiptOffsetParams(receiptOffsetBillPageQueryPo);
        List<ReceiptOffsetBillPageQueryDo> receiptOffsetBillPageQueryDos = new ArrayList<>();
        if (count > 0) {
            receiptOffsetBillPageQueryDos = receiptOffsetBillMapper.selectRecordsByReceiptOffsetParams(receiptOffsetBillPageQueryPo);
        }
        BasePageResponse<ReceiptOffsetBillResponse> response = new BasePageResponse<>();
        if (CollectionUtil.isNotEmpty(receiptOffsetBillPageQueryDos)) {
            List<ReceiptOffsetBillResponse> receiptOffsetBillResponses = new ArrayList<>();
            receiptOffsetBillPageQueryDos.forEach(r -> {
                ReceiptOffsetBillResponse receiptOffsetBillResponse = BeanUtil.copyProperties(r, ReceiptOffsetBillResponse.class);
                receiptOffsetBillResponse.setReceiptOffsetBillStatus(r.getBillStatus());
                receiptOffsetBillResponse.setReceiptOffsetBillStatusDesc(ReceiptOffsetBillStatusEnum.getDisPlayDescByType(r.getBillStatus()));
                receiptOffsetBillResponses.add(receiptOffsetBillResponse);
            });

            response.setCurrent(receiptOffsetBillBossPageQueryDto.getPageNum());
            response.setSize(receiptOffsetBillBossPageQueryDto.getPageSize());
            response.setTotal(count);
            response.setPages(count / receiptOffsetBillBossPageQueryDto.getPageSize() + 1);
            response.setRecords(receiptOffsetBillResponses);
        }
        log.info("queryReceiptOffsetBillPageInfosByBoss response:{}", JSONUtil.toJsonStr(response));
        return response;
    }

    @Override
    @DataPermission(sql = "com.hmy.finance.dal.mapper.receipt.ReceiptOffsetBillMapper.selectPage", userField = "sale_manager_id", deptField = "sale_manager_dept_id")
    public BasePageResponse<ReceiptOffsetBillAppPageQueryResponse> queryReceiptOffsetBillPageInfosByApp(ReceiptOffsetBillAppPageQueryRequest receiptOffsetBillAppPageQueryRequest) {
        log.info("queryReceiptOffsetBillPageInfosByApp request:{}", JSONUtil.toJsonStr(receiptOffsetBillAppPageQueryRequest));
        ReceiptOffsetBillAppPageQueryDto receiptOffsetBillAppPageQueryDto = BeanUtil.copyProperties(receiptOffsetBillAppPageQueryRequest, ReceiptOffsetBillAppPageQueryDto.class);
        receiptOffsetBillAppPageQueryDto.setReceiptOffsetBillStatus(ReceiptOffsetStatusConstant.RECEIPT_OFFSET_QUERY_STATUS_MAPPING.getOrDefault(receiptOffsetBillAppPageQueryDto.getBillStatus(), null));

        Page<ReceiptOffsetBillPo> page = new Page<>(receiptOffsetBillAppPageQueryDto.getPageNum(), receiptOffsetBillAppPageQueryDto.getPageSize());
        LambdaQueryWrapper<ReceiptOffsetBillPo> queryWrapper = new LambdaQueryWrapper<>();
        if (Objects.nonNull(receiptOffsetBillAppPageQueryDto.getReceiptOffsetBillStatus())) {
            queryWrapper.in(ReceiptOffsetBillPo::getBillStatus, receiptOffsetBillAppPageQueryDto.getReceiptOffsetBillStatus());
        }
        if (StringUtils.isNotBlank(receiptOffsetBillAppPageQueryDto.getReceiptOffsetBillNo())) {
            queryWrapper.like(ReceiptOffsetBillPo::getReceiptOffsetBillNo, receiptOffsetBillAppPageQueryDto.getReceiptOffsetBillNo());
        }
        if (StringUtils.isNotBlank(receiptOffsetBillAppPageQueryDto.getSearchParam())) {
            queryWrapper.and(wrapper -> wrapper.like(ReceiptOffsetBillPo::getReceiptOffsetBillNo, receiptOffsetBillAppPageQueryDto.getSearchParam()).or().like(ReceiptOffsetBillPo::getCustomerName, receiptOffsetBillAppPageQueryDto.getSearchParam()));
        }

        queryWrapper.orderByDesc(ReceiptOffsetBillPo::getCreateTime);//按创建时间倒序排序
        Page<ReceiptOffsetBillPo> pageResult = receiptOffsetBillMapper.selectPage(page, queryWrapper);

        List<ReceiptOffsetBillAppPageQueryResponse> receiptOffsetBillResponses = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(pageResult.getRecords())) {
            pageResult.getRecords().forEach(r -> {
                ReceiptOffsetBillAppPageQueryResponse receiptOffsetBillResponse = BeanUtil.copyProperties(r, ReceiptOffsetBillAppPageQueryResponse.class);
                if (Objects.isNull(ReceiptOffsetBillStatusEnum.getEnumByType(r.getBillStatus()))) {
                    throw new HMYRuntimeException(506800008);
                }
                if (Objects.nonNull(ReceiptedTypeEnum.getEnumByType(r.getReceiptedType()))) {
                    receiptOffsetBillResponse.setReceiptedDesc(ReceiptedTypeEnum.getDisPlayDescByType(r.getReceiptedType()));
//                    throw new HMYRuntimeException(506800013);
                }

                receiptOffsetBillResponse.setReceiptOffsetBillStatus(r.getBillStatus());
                receiptOffsetBillResponse.setReceiptOffsetBillStatusDesc(ReceiptOffsetBillStatusEnum.getDisPlayDescByType(r.getBillStatus()));
                receiptOffsetBillResponses.add(receiptOffsetBillResponse);
            });
        }
        BasePageResponse<ReceiptOffsetBillAppPageQueryResponse> response = new BasePageResponse<>();
        response.setCurrent(receiptOffsetBillAppPageQueryDto.getPageNum());
        response.setSize(receiptOffsetBillAppPageQueryDto.getPageSize());
        response.setTotal(pageResult.getTotal());
        response.setPages(pageResult.getPages());
        response.setRecords(receiptOffsetBillResponses);
        log.info("queryReceiptOffsetBillPageInfosByApp response:{}", JSONUtil.toJsonStr(response));
        return response;
    }

    @Override
    public ReceiptOffsetBillDetailResponse queryReceiptOffsetBillDetail(ReceiptOffsetBillDetailQueryRequest receiptOffsetBillDetailQueryRequest) {
        log.info("queryReceiptOffsetBillDetail request:{}", JSONUtil.toJsonStr(receiptOffsetBillDetailQueryRequest));
        ReceiptOffsetBillDetailQueryDto receiptOffsetBillDetailDto = BeanUtil.copyProperties(receiptOffsetBillDetailQueryRequest, ReceiptOffsetBillDetailQueryDto.class);

        LambdaQueryWrapper<ReceiptOffsetBillPo> queryWrapper = new LambdaQueryWrapper<>();
        if (Objects.nonNull(receiptOffsetBillDetailDto.getReceiptOffsetBillId())) {
            queryWrapper.eq(ReceiptOffsetBillPo::getReceiptOffsetBillId, receiptOffsetBillDetailDto.getReceiptOffsetBillId());
        }
        if (Objects.nonNull(receiptOffsetBillDetailDto.getReceiptOffsetBillNo()) && StringUtils.isNotBlank(receiptOffsetBillDetailDto.getReceiptOffsetBillNo())) {
            queryWrapper.eq(ReceiptOffsetBillPo::getReceiptOffsetBillNo, receiptOffsetBillDetailDto.getReceiptOffsetBillNo());
        }
        queryWrapper.eq(ReceiptOffsetBillPo::getIsDeleted, 0);
        ReceiptOffsetBillPo receiptOffsetBillDo = receiptOffsetBillMapper.selectOne(queryWrapper);
        if (Objects.isNull(receiptOffsetBillDo)) {
            throw new HMYRuntimeException(506800001);
        }
        receiptOffsetBillDetailDto.setReceiptOffsetBillId(receiptOffsetBillDo.getReceiptOffsetBillId());
        receiptOffsetBillDetailDto.setVoucherId(receiptOffsetBillDo.getVoucherId());

        //查receipt_contract_apportion_record表
        LambdaQueryWrapper<ReceiptContractApportionRecordPo> receiptContractQueryWrapper = new LambdaQueryWrapper<>();
        receiptContractQueryWrapper.eq(ReceiptContractApportionRecordPo::getReceiptOffsetBillId, receiptOffsetBillDetailDto.getReceiptOffsetBillId());
        receiptContractQueryWrapper.eq(ReceiptContractApportionRecordPo::getIsDeleted, 0);
        List<ReceiptContractApportionRecordPo> receiptContractApportionRecordPos = receiptContractApportionRecordMapper.selectList(receiptContractQueryWrapper);

        /*查询凭证文件表*/
        LambdaQueryWrapper<ReceiptVoucherPo> receiptVoucherQueryWrapper = new LambdaQueryWrapper<>();
        receiptVoucherQueryWrapper.eq(ReceiptVoucherPo::getId, receiptOffsetBillDetailDto.getVoucherId());
        receiptVoucherQueryWrapper.eq(ReceiptVoucherPo::getIsDeleted, 0);
        ReceiptVoucherPo receiptVoucherPo = receiptVoucherMapper.selectOne(receiptVoucherQueryWrapper);

        /*数据封装*/
        ReceiptOffsetBillDetailResponse response = new ReceiptOffsetBillDetailResponse();
        response.setReceiptOffsetBillId(receiptOffsetBillDo.getReceiptOffsetBillId());
        response.setReceiptOffsetBillNo(receiptOffsetBillDo.getReceiptOffsetBillNo());
        response.setSaleManagerId(receiptOffsetBillDo.getSaleManagerId());
        response.setSaleManagerName(receiptOffsetBillDo.getSaleManagerName());
        response.setCustomerId(receiptOffsetBillDo.getCustomerId());
        response.setCustomerName(receiptOffsetBillDo.getCustomerName());
        response.setProcessInstanceId(receiptOffsetBillDo.getProcessInstanceId());
        response.setRejectedOpinion(receiptOffsetBillDo.getRejectedOpinion());
        response.setReceiptOffsetBillStatus(receiptOffsetBillDo.getBillStatus());
        response.setReceiptOffsetBillStatusDesc(ReceiptOffsetBillStatusEnum.getDisPlayDescByType(receiptOffsetBillDo.getBillStatus()));
        response.setReceiptedTime(receiptOffsetBillDo.getReceiptedTime());
        response.setReceiptedAmount(receiptOffsetBillDo.getReceiptedAmount());
        response.setReceiptedType(receiptOffsetBillDo.getReceiptedType());
        response.setReceiptedDesc(ReceiptedTypeEnum.getDisPlayDescByType(receiptOffsetBillDo.getReceiptedType()));
        response.setCreateTime(receiptOffsetBillDo.getCreateTime());
        response.setRemarks(receiptOffsetBillDo.getRemarks());

        List<CustomerContactorResponse> customerContactors = new ArrayList<>();
        List<ContactorApportionResponse> contactorApportionInfos = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(receiptContractApportionRecordPos)) {
//            对receiptContractApportionRecordPos按customerContactorId属性进行分组
            Map<Long, List<ReceiptContractApportionRecordPo>> receiptContractApportionRecordMaps = receiptContractApportionRecordPos.stream().collect(Collectors.groupingBy(ReceiptContractApportionRecordPo::getCustomerContactorId));
            receiptContractApportionRecordMaps.forEach((contractId, receiptContractApportionRecords) -> {
                CustomerContactorResponse customerContactor = new CustomerContactorResponse();
                customerContactor.setCustomerContactorId(receiptContractApportionRecords.get(0).getCustomerContactorId());
                customerContactor.setCustomerContactorName(receiptContractApportionRecords.get(0).getCustomerContactorName());

                ContactorApportionResponse contactorApportion = new ContactorApportionResponse();
                contactorApportion.setCustomerContactorId(receiptContractApportionRecords.get(0).getCustomerContactorId());
                contactorApportion.setCustomerContactorName(receiptContractApportionRecords.get(0).getCustomerContactorName());
                contactorApportion.setContactorTotalArrearsAmount(receiptContractApportionRecords.get(0).getTotalArrearsAmount());//联系人目前总欠款金额
                contactorApportion.setBalanceAmount(receiptContractApportionRecords.get(0).getCustomerContactorExtensionInfo().getBalanceAmount());//核销单当前联系人账户余额
                contactorApportion.setApportionAmount(receiptContractApportionRecords.get(0).getCustomerContactorExtensionInfo().getApportionAmount());//联系人本次分摊核销金额
                contactorApportion.setContactorArrearsAmountAfterOffset(receiptContractApportionRecords.get(0).getCustomerContactorExtensionInfo().getContactorArrearsAmountAfterOffset());//联系人核销后欠款金额
                /*封装contractApportions*/
                List<ContractApportionResponse> contractApportions = new ArrayList<>();
                receiptContractApportionRecords.forEach(r -> {
                    ContractApportionResponse contractApportionResponse = new ContractApportionResponse();
                    contractApportionResponse.setContractId(r.getContractId());
                    contractApportionResponse.setContractNo(r.getContractNo());
                    contractApportionResponse.setContractTotalArrearsAmount(r.getTotalArrearsAmount());
                    contractApportionResponse.setContractRequireOffsetAmount(r.getSuggestOffsetAmount());
                    contractApportionResponse.setContractActualOffsetAmount(r.getActualOffsetAmount());
                    contractApportionResponse.setContractArrearsAmountAfterOffset(r.getOffsetedArrearsAmount());
                    contractApportions.add(contractApportionResponse);
                });
                contactorApportion.setContractApportions(contractApportions);

                customerContactors.add(customerContactor);
                contactorApportionInfos.add(contactorApportion);
            });
        }
        /*联系人信息*/
        response.setCustomerContactors(customerContactors);
        /*联系人分摊信息*/
        response.setContactorApportionInfos(contactorApportionInfos);

        /*客户账户费用*/
        response.setCustomerTotalArrearsAmount(receiptOffsetBillDo.getAccountExtensionInfos().getCustomerTotalArrearsAmount());//客户总欠款金额
        response.setCustomerOffsetAmount(receiptOffsetBillDo.getAccountExtensionInfos().getCustomerOffsetAmount());//客户本次核销金额(此核销单核销金额)
        response.setCustomerArrearsAmountAfterOffset(receiptOffsetBillDo.getAccountExtensionInfos().getCustomerArrearsAmountAfterOffset());//客户核销后总欠款金额-本单
        response.setCustomerBalanceAmount(receiptOffsetBillDo.getAccountExtensionInfos().getCustomerBalanceAmount());//客户账户余额-本单

        /*凭证*/
        ReceiptVoucherResponse receiptVoucher = new ReceiptVoucherResponse();
        receiptVoucher.setVoucherId(receiptVoucherPo.getId());
        receiptVoucher.setVoucherNo(receiptVoucherPo.getVoucherNo());
        receiptVoucher.setOssUrl(receiptVoucherPo.getAttachments().stream().map(VoucherAttachmentsJson::getOssUrl).collect(Collectors.toList()));
        response.setReceiptVoucher(receiptVoucher);

        return response;
    }

    @Override
    @DataPermission(sql = "com.hmy.finance.dal.mapper.receipt.ReceiptOffsetBillMapper.selectAuditingRecordsByCustomerIdAndCustomerContactorIds", tableAlias = "rob", userField = "sale_manager_id", deptField = "sale_manager_dept_id")
    public List<AuditingReceiptOffsetBillQueryResponse> queryAuditingReceiptOffsetBills(AuditingReceiptOffsetBillCountQueryRequest auditingReceiptOffsetBillCountQueryRequest) {
        log.info("queryAuditingReceiptOffsetBills request:{}", JSONUtil.toJsonStr(auditingReceiptOffsetBillCountQueryRequest));
        AuditingReceiptOffsetBillCountQueryDto auditingReceiptOffsetBillCountQueryDto = BeanUtil.copyProperties(auditingReceiptOffsetBillCountQueryRequest, AuditingReceiptOffsetBillCountQueryDto.class);
        List<ReceiptOffsetBillInfoDo> receiptOffsetBillInfoDetailDos = receiptOffsetBillMapper.selectAuditingRecordsByCustomerIdAndCustomerContactorIds(auditingReceiptOffsetBillCountQueryDto.getCustomerId(), auditingReceiptOffsetBillCountQueryDto.getCustomerContactorIds());

        /*数据封装*/
        List<AuditingReceiptOffsetBillQueryResponse> responses = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(receiptOffsetBillInfoDetailDos)) {
            responses = BeanUtil.copyToList(receiptOffsetBillInfoDetailDos, AuditingReceiptOffsetBillQueryResponse.class);
        }
        return responses;
    }

    @Override
    @Transactional
    public ReceiptOffsetBillCreateResponse createReceiptOffsetBill(ReceiptOffsetBillCreateRequest receiptOffsetBillCreateRequest) {
        log.info("ReceiptOffsetBillService#createReceiptOffsetBill: request{}", JSONUtil.toJsonStr(receiptOffsetBillCreateRequest));
        ReceiptOffsetBillCreateDto receiptOffsetBillCreateDto = BeanUtil.copyProperties(receiptOffsetBillCreateRequest, ReceiptOffsetBillCreateDto.class);

        this.setUserContextInfo(receiptOffsetBillCreateDto);
        receiptOffsetBillCreateDto.setSaleManagerId(receiptOffsetBillCreateDto.getCreatorId());
        receiptOffsetBillCreateDto.setSaleManagerName(receiptOffsetBillCreateDto.getCreatorName());
        receiptOffsetBillCreateDto.setSaleManagerDeptId(receiptOffsetBillCreateDto.getDeptIds().get(0));

        Long receiptOffsetBillId = identifierGenerator.nextId(receiptOffsetBillCreateRequest).longValue();
        String receiptOffsetBillNo = commonCodeGenerator.getNext(ReceiptOffsetConstant.RECEIPT_OFFSET_BILL_PREFIX, RedisKeyConstant.RECEIPT_OFFSET_CODE);
        String voucherBillNo = commonCodeGenerator.getNext(ReceiptOffsetConstant.VOUCHER_BILL_NO, RedisKeyConstant.VOUCHER_BILL_CODE);
        receiptOffsetBillCreateDto.setReceiptOffsetBillId(receiptOffsetBillId);
        receiptOffsetBillCreateDto.setReceiptOffsetBillNo(receiptOffsetBillNo);
        Long voucherId = identifierGenerator.nextId(receiptOffsetBillCreateRequest.getReceiptVoucher()).longValue();
        receiptOffsetBillCreateDto.getReceiptVoucher().setVoucherId(voucherId);
        receiptOffsetBillCreateDto.getReceiptVoucher().setVoucherNo(voucherBillNo);

        /*查询客户&联系人账户信息,并封装到dto*/
        ReceiptOffsetCustomerBalanceInfoDto customerBalanceInfoDto = BeanUtil.copyProperties(receiptOffsetBillCreateDto, ReceiptOffsetCustomerBalanceInfoDto.class);
        packageReceiptOffsetCustomerBalanceInfo(receiptOffsetBillCreateDto.getCustomerId(), customerBalanceInfoDto, receiptOffsetBillCreateDto.getContactorApportionInfos());
        receiptOffsetBillCreateDto.setCustomerTotalArrearsAmount(customerBalanceInfoDto.getCustomerTotalArrearsAmount());//客户合同欠款总额
        receiptOffsetBillCreateDto.setCustomerBalanceAmount(customerBalanceInfoDto.getCustomerBalanceAmount());//客户账户余额
        receiptOffsetBillCreateDto.setCustomerArrearsAmountAfterOffset(customerBalanceInfoDto.getCustomerArrearsAmountAfterOffset());//核销后欠款金额

        /*判断合同是否有应核尽核：不能在联系人下所有合同没有核销完的情况下联系人账户能有钱*/
        contactorApportionReceiptOffsetChecker(receiptOffsetBillCreateDto.getContactorApportionInfos());


        /*先创建流程*/
        StartProcessInstanceResponse processResponse = createFlowProcess(receiptOffsetBillCreateDto);
        receiptOffsetBillCreateDto.setProcessInstanceId(processResponse.getProcessInstanceId());

        /*数据封装及保存*/
        ReceiptOffsetBillPo receiptOffsetBillDo = new ReceiptOffsetBillPo();
        receiptOffsetBillCreateDto.dto2ReceiptOffsetBillPoBuilder(receiptOffsetBillDo);
        log.info(JSONUtil.toJsonStr(receiptOffsetBillDo));

        /*再插入数据*/
        Integer flag = receiptOffsetBillMapper.insert(receiptOffsetBillDo);
        if (flag > 0) {
            List<ReceiptContractApportionRecordPo> totalReceiptContractApportionRecords = new ArrayList<>();
            if (CollectionUtil.isNotEmpty(receiptOffsetBillCreateDto.getContactorApportionInfos())) {
                List<ContactorApportionDto> contactorApportionInfos = receiptOffsetBillCreateDto.getContactorApportionInfos();
                contactorApportionInfos.forEach(contactorApportionDto -> {
                    List<ReceiptContractApportionRecordPo> receiptContractApportionRecordPos = new ArrayList<>();
                    receiptOffsetBillCreateDto.dto2ReceiptContractApportionRecordPoBuilder(contactorApportionDto, receiptContractApportionRecordPos);
                    totalReceiptContractApportionRecords.addAll(receiptContractApportionRecordPos);
                });
            }
            receiptContractApportionRecordMapper.batchInsertReceiptContractApportionRecords(totalReceiptContractApportionRecords);

            ReceiptVoucherPo receiptVoucherPo = new ReceiptVoucherPo();
            receiptOffsetBillCreateDto.dto2ReceiptVoucherPoBuilder(receiptVoucherPo);
            receiptVoucherMapper.insert(receiptVoucherPo);
        }
        ReceiptOffsetBillCreateResponse response = new ReceiptOffsetBillCreateResponse();
        response.setReceiptOffsetBillId(receiptOffsetBillCreateDto.getReceiptOffsetBillId());
        response.setReceiptOffsetBillNo(receiptOffsetBillCreateDto.getReceiptOffsetBillNo());
        response.setSuccess(flag > 0 ? Boolean.TRUE : Boolean.FALSE);
        log.info("ReceiptOffsetBillService#createReceiptOffsetBill: response{}", JSONUtil.toJsonStr(response));
        return response;
    }

    @Override
    @Transactional
    public ReceiptOffsetBillEditResponse editReceiptOffsetBill(ReceiptOffsetBillEditRequest receiptOffsetBillEditRequest) {
        log.info("ReceiptOffsetBillService#editReceiptOffsetBill: request{}", JSONUtil.toJsonStr(receiptOffsetBillEditRequest));
        ReceiptOffsetBillEditDto receiptOffsetBillEditDto = BeanUtil.copyProperties(receiptOffsetBillEditRequest, ReceiptOffsetBillEditDto.class);
        this.setUserContextInfo(receiptOffsetBillEditDto);
        receiptOffsetBillEditDto.setSaleManagerId(receiptOffsetBillEditDto.getCreatorId());
        receiptOffsetBillEditDto.setSaleManagerName(receiptOffsetBillEditDto.getCreatorName());
        receiptOffsetBillEditDto.setSaleManagerDeptId(receiptOffsetBillEditDto.getDeptIds().get(0));

        /*确认当前单据是否能否编辑;*/
        Long receiptOffsetBillId = receiptOffsetBillEditDto.getReceiptOffsetBillId();
        ReceiptOffsetBillPo receiptOffsetBillDo = selectReceiptOffsetBillById(receiptOffsetBillId);
        if (Objects.isNull(receiptOffsetBillDo) || Objects.isNull(receiptOffsetBillDo.getBillStatus())) {
            throw new HMYRuntimeException(506800001);
        }
        if (!ReceiptOffsetStatusConstant.BILL_STATUS_CAN_EDIT.contains(receiptOffsetBillDo.getBillStatus())) {
            throw new HMYRuntimeException(506800009);
        }
        receiptOffsetBillEditDto.setReceiptOffsetBillNo(receiptOffsetBillDo.getReceiptOffsetBillNo());
        receiptOffsetBillEditDto.getReceiptVoucher().setVoucherId(receiptOffsetBillDo.getVoucherId());

        /*查询客户&联系人账户信息,并封装到dto*/
        ReceiptOffsetCustomerBalanceInfoDto customerBalanceInfoDto = BeanUtil.copyProperties(receiptOffsetBillEditDto, ReceiptOffsetCustomerBalanceInfoDto.class);
        packageReceiptOffsetCustomerBalanceInfo(receiptOffsetBillEditDto.getCustomerId(), customerBalanceInfoDto, receiptOffsetBillEditDto.getContactorApportionInfos());
        receiptOffsetBillEditDto.setCustomerBalanceAmount(customerBalanceInfoDto.getCustomerBalanceAmount());//客户账户余额
        receiptOffsetBillEditDto.setCustomerTotalArrearsAmount(customerBalanceInfoDto.getCustomerTotalArrearsAmount());//客户合同欠款总额
        receiptOffsetBillEditDto.setCustomerArrearsAmountAfterOffset(customerBalanceInfoDto.getCustomerArrearsAmountAfterOffset());//核销后欠款金额

        /*判断是否应核尽核*/
        contactorApportionReceiptOffsetChecker(receiptOffsetBillEditDto.getContactorApportionInfos());

        //数据封装及更新
        LambdaQueryWrapper<ReceiptOffsetBillPo> updateQueryWrapper = new LambdaQueryWrapper<>();
        updateQueryWrapper.eq(ReceiptOffsetBillPo::getReceiptOffsetBillId, receiptOffsetBillEditDto.getReceiptOffsetBillId());
        updateQueryWrapper.eq(ReceiptOffsetBillPo::getIsDeleted, 0);
        ReceiptOffsetBillPo receiptOffsetBillPo = new ReceiptOffsetBillPo();
        receiptOffsetBillEditDto.dto2ReceiptOffsetBillPoBuilder(receiptOffsetBillPo);
        log.info(JSONUtil.toJsonStr(receiptOffsetBillPo));

        Integer flag = receiptOffsetBillMapper.update(receiptOffsetBillPo, updateQueryWrapper);
        if (flag > 0) {
            List<ReceiptContractApportionRecordPo> totalReceiptContractApportionRecords = new ArrayList<>();
            if (CollectionUtil.isNotEmpty(receiptOffsetBillEditDto.getContactorApportionInfos())) {
                List<ContactorApportionDto> contactorApportionInfos = receiptOffsetBillEditDto.getContactorApportionInfos();
                contactorApportionInfos.forEach(contactorApportionDto -> {
                    List<ReceiptContractApportionRecordPo> receiptContractApportionRecordPos = new ArrayList<>();
                    receiptOffsetBillEditDto.dto2ReceiptContractApportionRecordPoBuilder(contactorApportionDto, receiptContractApportionRecordPos);
                    totalReceiptContractApportionRecords.addAll(receiptContractApportionRecordPos);
                });
            }
            LambdaQueryWrapper<ReceiptContractApportionRecordPo> deleteWrapper = new LambdaQueryWrapper<>();
            deleteWrapper.eq(ReceiptContractApportionRecordPo::getReceiptOffsetBillId, receiptOffsetBillEditDto.getReceiptOffsetBillId());
            deleteWrapper.eq(ReceiptContractApportionRecordPo::getIsDeleted, 0);
            receiptContractApportionRecordMapper.delete(deleteWrapper);
            receiptContractApportionRecordMapper.batchInsertReceiptContractApportionRecords(totalReceiptContractApportionRecords);

            ReceiptVoucherPo receiptVoucherPo = new ReceiptVoucherPo();
            receiptOffsetBillEditDto.dto2ReceiptVoucherPoBuilder(receiptVoucherPo);
            LambdaQueryWrapper<ReceiptVoucherPo> receiptVoucherUpdateWrapper = new LambdaQueryWrapper<>();
            receiptVoucherUpdateWrapper.eq(ReceiptVoucherPo::getId, receiptOffsetBillEditDto.getReceiptVoucher().getVoucherId());
            receiptVoucherUpdateWrapper.eq(ReceiptVoucherPo::getIsDeleted, 0);
            receiptVoucherMapper.update(receiptVoucherPo, receiptVoucherUpdateWrapper);

            /*创建流程*/
            ReceiptOffsetBillProcessVariableDto variableDto = BeanUtil.copyProperties(receiptOffsetBillPo, ReceiptOffsetBillProcessVariableDto.class);
            variableDto.setProcessCurrentTaskId(receiptOffsetBillEditDto.getProcessCurrentTaskId());
            variableDto.setReceiptOffsetBillId(receiptOffsetBillEditDto.getReceiptOffsetBillId());
            variableDto.setReceiptOffsetBillNo(receiptOffsetBillEditDto.getReceiptOffsetBillNo());
            variableDto.setProcessInstanceId(receiptOffsetBillDo.getProcessInstanceId());
            ApprovalTaskResponse approvalTaskResponse = editResubmitFlowProcess(variableDto);
            if (!approvalTaskResponse.getSuccess()) {
                throw new HMYRuntimeException(506800014, new Object[]{receiptOffsetBillEditDto.getReceiptOffsetBillNo()});
            }

        }

        ReceiptOffsetBillEditResponse response = new ReceiptOffsetBillEditResponse();
        response.setReceiptOffsetBillId(receiptOffsetBillEditDto.getReceiptOffsetBillId());
        response.setReceiptOffsetBillNo(receiptOffsetBillEditDto.getReceiptOffsetBillNo());
        response.setSuccess(flag > 0 ? Boolean.TRUE : Boolean.FALSE);
        log.info("ReceiptOffsetBillService#editReceiptOffsetBill: response{}", JSONUtil.toJsonStr(response));
        return response;
    }

    /**
     * 判断合同是否有应核尽核：不能在联系人下所有合同没有核销完的情况下联系人账户能有钱
     *
     * @param contactorApportionInfos 联系人分摊信息
     */
    private void contactorApportionReceiptOffsetChecker(List<ContactorApportionDto> contactorApportionInfos) {
        contactorApportionInfos.forEach(contactorApportionDto -> {
            BigDecimal totalContractApportionAmount = contactorApportionDto.getContractApportions().stream().map(ContractApportionDto::getContractActualOffsetAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            if (contactorApportionDto.getApportionAmount().subtract(totalContractApportionAmount).compareTo(BigDecimal.ZERO) > 0) {
                //如果联系人分摊金额大于合同实际核销金额情况下，说明有联系人有余额，此时查看是否有合同没有应核尽核
                contactorApportionDto.getContractApportions().forEach(contractApportionDto -> {
                    if (contractApportionDto.getContractRequireOffsetAmount().subtract(contractApportionDto.getContractActualOffsetAmount()).compareTo(BigDecimal.ZERO) > 0) {
                        throw new HMYRuntimeException(506800026, new Object[]{contactorApportionDto.getCustomerContactorName(), contractApportionDto.getContractNo()});
                    }
                });
            }
        });
    }

    /**
     * 账户金额数据封装器
     */
    private void packageReceiptOffsetCustomerBalanceInfo(Long customerId, ReceiptOffsetCustomerBalanceInfoDto customerBalanceInfoDto, List<ContactorApportionDto> contactorApportionInfos) {
        log.info("packageReceiptOffsetCustomerBalanceInfo request:{}", JSONUtil.toJsonStr(contactorApportionInfos));

        /*查询最新的客户余额，总欠款*/
        CustomerBalanceAccountInfoDto customerBalanceAccountInfo = new CustomerBalanceAccountInfoDto();
        customerBalanceAccountInfo.setCustomerId(customerId);
        customerBalanceAccountInfo.setCustomerOffsetAmount(customerBalanceInfoDto.getCustomerOffsetAmount());
        CustomerBalanceAccountInfoResponse customerBalanceAccount = customerBalanceAccountService.queryCustomerBalanceAccountInfo(customerBalanceAccountInfo);

        /*如果前端传的余额和后台的不一样，则报错提醒*/
        if (!(customerBalanceInfoDto.getCustomerBalanceAmount().compareTo(customerBalanceAccount.getCustomerBalanceAmount()) == 0)) {
            throw new HMYRuntimeException(506800015);
        }
        /*如果前端传的客户总欠款金额和后台的不一样，则报错提醒*/
        if (!(customerBalanceInfoDto.getCustomerTotalArrearsAmount().compareTo(customerBalanceAccount.getCustomerContractTotalArrearsAmount()) == 0)) {
            throw new HMYRuntimeException(506800016);
        }
        customerBalanceInfoDto.setCustomerBalanceAmount(customerBalanceAccount.getCustomerBalanceAmount());//客户账户余额
        customerBalanceInfoDto.setCustomerTotalArrearsAmount(customerBalanceAccount.getCustomerContractTotalArrearsAmount());//客户合同欠款总额
        customerBalanceInfoDto.setCustomerArrearsAmountAfterOffset(customerBalanceAccount.getCustomerArrearsAmountAfterOffset());//核销后欠款金额

        if (CollectionUtil.isNotEmpty(contactorApportionInfos)) {
            /*查询联系人最新的余额，总欠款*/
            CustomerContactorBalanceAccountInfoDto customerContactorBalanceAccountInfoDto = new CustomerContactorBalanceAccountInfoDto();
            customerContactorBalanceAccountInfoDto.setCustomerId(customerId);
            customerContactorBalanceAccountInfoDto.setCustomerContactorIds(contactorApportionInfos.stream().map(r -> r.getCustomerContactorId()).collect(Collectors.toList()));
            CustomerContactorBalanceAccountInfoResponse customerContactorBalanceAccounts = customerContactorBalanceAccountService.queryCustomerContactorBalanceAccountInfo(customerContactorBalanceAccountInfoDto);

            /*查询合同级别的欠款信息*/
            List<Long> contractIds = new ArrayList<>();//合同ids
            contactorApportionInfos.forEach(r -> {
                contractIds.addAll(r.getContractApportions().stream().map(ContractApportionDto::getContractId).collect(Collectors.toList()));
            });
            List<ContractTotalReceivableRdto> contractTotalReceivables = receivableInventoryService.queryContractTotalReceivableAmountByContractIds(contractIds);

            contactorApportionInfos.forEach(contactorApportionDto -> {
                if (customerContactorBalanceAccounts.getContactorBalanceAccountInfos().stream().anyMatch(c -> contactorApportionDto.getCustomerContactorId().equals(c.getContactorId()))) {
                    ContactorBalanceAccountInfoResponse contactorBalanceAccount = customerContactorBalanceAccounts.getContactorBalanceAccountInfos().stream().filter(c -> contactorApportionDto.getCustomerContactorId().equals(c.getContactorId())).findAny().get();
                    /*如果前端传的余额和后台的不一样，则报错提醒*/
                    if (!(contactorApportionDto.getBalanceAmount().compareTo(contactorBalanceAccount.getContactorBalanceAmount()) == 0)) {
                        log.info("联系人:id{},name:{}余额不一致，前端传的余额：{}，后台查询的余额：{}", contactorApportionDto.getCustomerContactorId(), contactorApportionDto.getCustomerContactorName(), contactorApportionDto.getBalanceAmount(), contactorBalanceAccount.getContactorBalanceAmount());
                        throw new HMYRuntimeException(506800018, new Object[]{contactorApportionDto.getCustomerContactorName()});
                    }
                    contactorApportionDto.setContactorTotalArrearsAmount(contactorBalanceAccount.getCustomerContractTotalArrearsAmount());//联系人总欠款金额
                    contactorApportionDto.setBalanceAmount(contactorBalanceAccount.getContactorBalanceAmount());//联系人余额
                    contactorApportionDto.setContactorArrearsAmountAfterOffset(contactorBalanceAccount.getCustomerContractTotalArrearsAmount().subtract(contactorApportionDto.getApportionAmount()));//联系人核销后总欠款金额,计算:
                } else {
                    log.info("没有找到对应的联系人id数据,{}，可能是联系人已经没有欠款。", JSON.toJSON(contactorApportionDto));
                    throw new HMYRuntimeException(506800017, new Object[]{contactorApportionDto.getCustomerContactorName()});
                }

                /*更新最新的合同欠款数据 */
                if (CollectionUtil.isNotEmpty(contactorApportionDto.getContractApportions())) {
                    contactorApportionDto.getContractApportions().forEach(contractApportionDto -> {
                        if (contractTotalReceivables.stream().anyMatch(c -> contractApportionDto.getContractId().equals(c.getContractId()))) {
                            /*如果合同没欠款了，不应该核销，报错。*/
                            ContractTotalReceivableRdto contractTotalReceivable = contractTotalReceivables.stream().filter(c -> contractApportionDto.getContractId().equals(c.getContractId())).findAny().get();
                            if (contractTotalReceivable.getTotalReceivableAmount().compareTo(BigDecimal.ZERO) > 0) {
                                //查询合同欠款信息
                                contractApportionDto.setContractArrearsAmountAfterOffset(contractTotalReceivable.getTotalReceivableAmount().subtract(contractApportionDto.getContractActualOffsetAmount()));//合同总欠款金额
                                contractApportionDto.setContractTotalArrearsAmount(contractTotalReceivable.getTotalReceivableAmount());//客户核销后总欠款金额
                            } else {
                                log.info("合同目前不存在欠款,contractTotalReceivables:{}", JSON.toJSON(contractTotalReceivables));
                                throw new HMYRuntimeException(506800007, new Object[]{contractApportionDto.getContractNo()});
                            }
                        } else {
                            log.info("没有找到对应的合同id数据,{}，可能是合同已经没有欠款。请刷新后重试", JSON.toJSON(contractTotalReceivables));
                            throw new HMYRuntimeException(506800006);
                        }
                    });
                }
            });
        }
    }


    @Override
    @Transactional
    public ReceiptOffsetBillDeleteResponse deleteReceiptOffsetBill(ReceiptOffsetBillDeleteRequest receiptOffsetBillDeleteRequest) {
        log.info("ReceiptOffsetBillService#deleteReceiptOffsetBill:{}", JSONUtil.toJsonStr(receiptOffsetBillDeleteRequest));
        ReceiptOffsetBillDeleteDto receiptOffsetBillDeleteDto = BeanUtil.copyProperties(receiptOffsetBillDeleteRequest, ReceiptOffsetBillDeleteDto.class);

        /*step1.查询order信息判断是否可以进行删除;*/
        Long receiptOffsetBillId = receiptOffsetBillDeleteDto.getReceiptOffsetBillId();
        ReceiptOffsetBillPo receiptOffsetBillDo = selectReceiptOffsetBillById(receiptOffsetBillId);
        if (Objects.isNull(receiptOffsetBillDo) || Objects.isNull(receiptOffsetBillDo.getBillStatus())) {
            throw new HMYRuntimeException(506800001);
        }
        if (!ReceiptOffsetStatusConstant.BILL_STATUS_CAN_DELETE.contains(receiptOffsetBillDo.getBillStatus())) {
            throw new HMYRuntimeException(506800010);
        }

        /*step2.1删除收款核销申请单*/
        LambdaQueryWrapper<ReceiptOffsetBillPo> deleteWrapper = new LambdaQueryWrapper<>();
        deleteWrapper.eq(ReceiptOffsetBillPo::getReceiptOffsetBillId, receiptOffsetBillDeleteDto.getReceiptOffsetBillId());
        deleteWrapper.eq(ReceiptOffsetBillPo::getIsDeleted, 0);
        Integer flag = receiptOffsetBillMapper.delete(deleteWrapper);
        /*step2.2 删除receipt_contract_apportion_record表*/
        if (flag > 0) {
            LambdaQueryWrapper<ReceiptContractApportionRecordPo> deleteApportionRecordWrapper = new LambdaQueryWrapper<>();
            deleteApportionRecordWrapper.eq(ReceiptContractApportionRecordPo::getReceiptOffsetBillId, receiptOffsetBillDeleteDto.getReceiptOffsetBillId());
            deleteApportionRecordWrapper.eq(ReceiptContractApportionRecordPo::getIsDeleted, 0);
            receiptContractApportionRecordMapper.delete(deleteApportionRecordWrapper);
        }
        /*step3.结果封装*/
        ReceiptOffsetBillDeleteResponse response = new ReceiptOffsetBillDeleteResponse();
        response.setReceiptOffsetBillId(receiptOffsetBillDo.getReceiptOffsetBillId());
        response.setReceiptOffsetBillNo(receiptOffsetBillDo.getReceiptOffsetBillNo());
        response.setSuccess(flag > 0 ? Boolean.TRUE : Boolean.FALSE);
        return response;
    }

    @Override
    public ContactorApportionsQueryResponse queryContactorApportions(ContactorApportionsQueryRequest contactorApportionsQueryRequest) {
        log.info("receiptOffsetBillService#queryContactorApportions request:{}", JSON.toJSON(contactorApportionsQueryRequest));
        ContactorApportionsQueryDto contactorApportionsQueryDto = BeanUtil.copyProperties(contactorApportionsQueryRequest, ContactorApportionsQueryDto.class);

        /*1.查询联系人下账户信息并封装到dto*/
        CustomerContactorBalanceAccountInfoDto customerContactorBalanceAccountInfoDto = new CustomerContactorBalanceAccountInfoDto();
        customerContactorBalanceAccountInfoDto.setCustomerId(contactorApportionsQueryDto.getCustomerId());
        customerContactorBalanceAccountInfoDto.setCustomerContactorIds(contactorApportionsQueryDto.getContactorApportions().stream().map(ContactorApportionQueryDto::getCustomerContactorId).collect(Collectors.toList()));
        CustomerContactorBalanceAccountInfoResponse customerContactorBalanceAccounts = customerContactorBalanceAccountService.queryCustomerContactorBalanceAccountInfo(customerContactorBalanceAccountInfoDto);

        contactorApportionsQueryDto.getContactorApportions().forEach(contactorApportion -> {
            if (customerContactorBalanceAccounts.getContactorBalanceAccountInfos().stream().anyMatch(c -> contactorApportion.getCustomerContactorId().equals(c.getContactorId()))) {
                ContactorBalanceAccountInfoResponse contactorBalanceAccount = customerContactorBalanceAccounts.getContactorBalanceAccountInfos().stream().filter(c -> contactorApportion.getCustomerContactorId().equals(c.getContactorId())).findAny().get();
                contactorApportion.setCustomerContactorName(contactorBalanceAccount.getContactorName());
                contactorApportion.setContactorTotalArrearsAmount(contactorBalanceAccount.getCustomerContractTotalArrearsAmount());//联系人总欠款金额
                contactorApportion.setBalanceAmount(contactorBalanceAccount.getContactorBalanceAmount());//联系人余额
                contactorApportion.setContactorArrearsAmountAfterOffset(contactorBalanceAccount.getCustomerContractTotalArrearsAmount().subtract(contactorApportion.getApportionAmount()));//联系人核销后总欠款金额,计算:
            } else {
                log.info("contactorApportion:{}", JSON.toJSON(contactorApportion));
                throw new HMYRuntimeException(506800004, new Object[]{contactorApportion.getCustomerContactorId()});
            }
        });

        /*2.查询联系人下所有合同信息及欠款金额并封装到dto*/
        List<Long> contactorIds = contactorApportionsQueryDto.getContactorApportions().stream().map(ContactorApportionQueryDto::getCustomerContactorId).collect(Collectors.toList());
        LambdaQueryWrapper<ReceivableInventoryPo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ReceivableInventoryPo::getCustomerId, contactorApportionsQueryDto.getCustomerId());
        queryWrapper.in(ReceivableInventoryPo::getSignatoryId, contactorIds);
        queryWrapper.eq(ReceivableInventoryPo::getIsDeleted, 0);
        List<ReceivableInventoryPo> receivableInventoryDos = receivableInventoryMapper.selectList(queryWrapper);

        List<Long> contractIds = receivableInventoryDos.stream().map(ReceivableInventoryPo::getContractId).collect(Collectors.toList());
//        List<ContractEarliestRentalPo> contractEarliestBillDos = deviceDailyBillMapper.selectEarliestRecordsByContractIds(contractIds);
        List<ContractEarliestRentalPo> contractEarliestRentalPos = deviceRentalRecordMapper.selectEarliestRentalRecordsByContractIds(contractIds);

        //现将合同欠款金额进行数据封装
        contractApportionsPackager(contactorApportionsQueryDto.getContactorApportions(), contractEarliestRentalPos, receivableInventoryDos);
        log.info("receiptOffsetBillService#queryContactorApportions contractApportionDTO:{}", JSON.toJSON(contactorApportionsQueryDto));
        /*按联系人分摊纬度顺序进行合同分摊*/
        for (ContactorApportionQueryDto contactorApportionQueryDto : contactorApportionsQueryDto.getContactorApportions()) {
            contactorApportionQueryDto.getContractApportions().sort(Comparator.comparing(ContractApportionDto::getSerialNo));
            /*对逾期范围进行枚举 start*/
            List<Integer> overdueDayArray = overdueDayTypeArrayGetter(contactorApportionQueryDto);
            /*对逾期范围进行枚举 end*/
            BigDecimal remainingAmount = contactorApportionQueryDto.getApportionAmount();
            /*step1.逾期分摊*/
            for (Integer overdueDay : overdueDayArray) {
                /*分摊逻辑处理*/
                remainingAmount = overdueAllocatePaymentsHandler(remainingAmount, contactorApportionQueryDto.getContractApportions(), overdueDay);
            }
            /*step2.非逾期分摊*/
            if (remainingAmount.compareTo(BigDecimal.ZERO) > 0) {
                remainingAmount = nonOverdueAllocatePaymentsHandler(remainingAmount, contactorApportionQueryDto.getContractApportions());
            }

        }
        log.info("receiptOffsetBillService#queryContactorApportions contractApportionDTO:{}", JSON.toJSON(contactorApportionsQueryDto));

        //封装返回数据
        ContactorApportionsQueryResponse response = new ContactorApportionsQueryResponse();
        response.setCustomerId(contactorApportionsQueryDto.getCustomerId());
        response.setCustomerName(contactorApportionsQueryDto.getCustomerName());
        response.setTotalApportionAmount(contactorApportionsQueryDto.getTotalApportionAmount());

        List<ContactorApportionResponse> contactorApportions = BeanUtil.copyToList(contactorApportionsQueryDto.getContactorApportions(), ContactorApportionResponse.class);
        response.setContactorApportions(contactorApportions);
        log.info("receiptOffsetBillService#queryContactorApportions response:{}", JSON.toJSON(response));
        return response;
    }

    /**
     * contractApportionsPackage封装器
     */
    private void contractApportionsPackager(List<ContactorApportionQueryDto> contactorApportions, List<ContractEarliestRentalPo> contractEarliestBillDos, List<ReceivableInventoryPo> receivableInventoryDos) {
        contactorApportions.forEach(contactorApportion -> {
            List<ContractApportionDto> contractApportions = new ArrayList<>();

            Long customerContactorId = contactorApportion.getCustomerContactorId();
            List<ContractEarliestRentalPo> contractEarliests = contractEarliestBillDos.stream().filter(r -> customerContactorId.equals(r.getContactorId())).collect(Collectors.toList());
            contractEarliests.sort(Comparator.comparing(ContractEarliestRentalPo::getRentalStartTime).reversed());
            Integer serialNo = 1;
            for (ContractEarliestRentalPo contractEarliest : contractEarliests) {
                ContractApportionDto contractApportionDto = new ContractApportionDto();
                if (!receivableInventoryDos.stream().anyMatch(r -> contractEarliest.getContractId().equals(r.getContractId()))) {
                    throw new HMYRuntimeException(506800012, new Object[]{contractEarliest.getContactorId(), contractEarliest.getContactorId()});
                }
                ReceivableInventoryPo contactorReceivables = receivableInventoryDos.stream().filter(r -> contractEarliest.getContractId().equals(r.getContractId())).findFirst().get();
                contractApportionDto.setSerialNo(serialNo);
                contractApportionDto.setContractId(contactorReceivables.getContractId());
                contractApportionDto.setContractNo(contactorReceivables.getContractNo());
                contractApportionDto.setContractTotalArrearsAmount(contactorReceivables.getTotalReceivableAmount());
                contractApportionDto.setContractRequireOffsetAmount(contactorReceivables.getTotalReceivableAmount());
                List<ContractApportionDto.OverdueDetailDto> overdueDetails = BeanUtil.copyToList(contactorReceivables.getOverdueDetail(), ContractApportionDto.OverdueDetailDto.class);
                contractApportionDto.setOverdueDetails(overdueDetails);
                serialNo++;
                contractApportions.add(contractApportionDto);
            }
            contactorApportion.setContractApportions(contractApportions);
        });
    }

    private List<Integer> overdueDayTypeArrayGetter(ContactorApportionQueryDto contactorApportionQueryDto) {
        /*对逾期范围进行枚举 start*/
        List<Integer> overdueDaysArrays = new ArrayList<>();
        /*对contractApportionDtos中的overdueDetails的overdueDaysStart属性进行取值去重并倒序排序*/
        contactorApportionQueryDto.getContractApportions().forEach(contractApportionDto -> {
            overdueDaysArrays.addAll(contractApportionDto.getOverdueDetails().stream().map(ContractApportionDto.OverdueDetailDto::getOverdueDaysStart).collect(Collectors.toList()));
        });
        List<Integer> overdueDayArray = overdueDaysArrays.stream().distinct().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
        return overdueDayArray;
    }

    private BigDecimal nonOverdueAllocatePaymentsHandler(BigDecimal remainingAmount, List<ContractApportionDto> contractApportions) {
        if (CollectionUtil.isNotEmpty(contractApportions)) {
            for (ContractApportionDto contractApportionDto : contractApportions) {
                BigDecimal nonOverduePayments = contractApportionDto.getContractTotalArrearsAmount().subtract(contractApportionDto.getContractSuggestOffsetAmount());
                BigDecimal amountToAllocate = nonOverduePayments.min(remainingAmount);
                BigDecimal suggestOffsetAmount = contractApportionDto.getContractSuggestOffsetAmount().add(amountToAllocate);
                contractApportionDto.setContractSuggestOffsetAmount(suggestOffsetAmount);
                remainingAmount = remainingAmount.subtract(amountToAllocate);
            }
        }
        return remainingAmount;
    }

    /**
     * 逾期核销分摊处理器
     *
     * @param remainingAmount    核销剩余金额
     * @param contractApportions 合同分摊信息
     * @param overdueDay         逾期期数
     */
    private BigDecimal overdueAllocatePaymentsHandler(BigDecimal remainingAmount, List<ContractApportionDto> contractApportions, Integer overdueDay) {
        if (CollectionUtil.isNotEmpty(contractApportions)) {
            for (ContractApportionDto contractApportionDto : contractApportions) {
                if (contractApportionDto.getOverdueDetails().stream().anyMatch(o -> o.getOverdueDaysStart().equals(overdueDay))) {
                    ContractApportionDto.OverdueDetailDto overdueDetail = contractApportionDto.getOverdueDetails().stream().filter(o -> o.getOverdueDaysStart().equals(overdueDay)).findAny().get();
                    if (remainingAmount.compareTo(BigDecimal.ZERO) > 0) {
                        if (overdueDetail.getOverdueAmount().compareTo(BigDecimal.ZERO) > 0) {
                            BigDecimal amountToAllocate = overdueDetail.getOverdueAmount().min(remainingAmount);
                            BigDecimal suggestOffsetAmount = contractApportionDto.getContractSuggestOffsetAmount().add(amountToAllocate);
                            contractApportionDto.setContractSuggestOffsetAmount(suggestOffsetAmount);
                            remainingAmount = remainingAmount.subtract(amountToAllocate);
                        }
                    }
                }
            }
        }
        return remainingAmount;
    }

    @Override
//    @Transactional
    public Boolean doReceiptBillOffsetHandler(ReceiptBillOffsetHandlerDto receiptBillOffsetHandlerDto) {
        log.info("ReceiptOffsetBillService#doReceiptBillOffsetHandler request:{}", JSON.toJSON(receiptBillOffsetHandlerDto));
        /*step1.查询核销单数据*/
        Long receiptOffsetBillId = receiptBillOffsetHandlerDto.getReceiptOffsetBillId();
        ReceiptOffsetBillPo receiptOffsetBillDo = selectReceiptOffsetBillById(receiptOffsetBillId);

        if (Objects.isNull(receiptOffsetBillDo)) {
            log.info("ReceiptOffsetBillService#doReceiptBillOffsetHandler 该核销单:{}异常，没有被找到。", receiptOffsetBillId);
            throw new HMYRuntimeException("该核销单异常，没有被找到");
        }
        if (ReceiptOffsetBillStatusEnum.OFFSET_SUCCESS.getStatusCode().equals(receiptOffsetBillDo.getBillStatus())) {
            log.info("ReceiptOffsetBillService#doReceiptBillOffsetHandler 该核销单:{}已经被核销。", receiptOffsetBillId);
            return Boolean.TRUE;
        }
        //todo:添加核销异常告警处理

        LambdaQueryWrapper<ReceiptContractApportionRecordPo> receiptContractQueryWrapper = new LambdaQueryWrapper<>();
        receiptContractQueryWrapper.eq(ReceiptContractApportionRecordPo::getReceiptOffsetBillId, receiptOffsetBillId);
        receiptContractQueryWrapper.eq(ReceiptContractApportionRecordPo::getIsDeleted, 0);
        List<ReceiptContractApportionRecordPo> receiptContractApportionRecordDos = receiptContractApportionRecordMapper.selectList(receiptContractQueryWrapper);

        /*step2.客户账户充值;*/
        CustomerIncomeDto customerIncomeDto = new CustomerIncomeDto();
        customerIncomeDto.setCustomerId(receiptOffsetBillDo.getCustomerId());
        customerIncomeDto.setAmount(receiptOffsetBillDo.getReceiptedAmount());
        customerIncomeDto.setBusinessType(AccountTradeBusinessTypeEnum.APPORTION);
        customerIncomeDto.setBusinessBillId(receiptBillOffsetHandlerDto.getReceiptOffsetBillId());
        customerIncomeDto.setFeeIncurredTime(receiptOffsetBillDo.getReceiptedTime());
        TradeRdto customerTradeRdto = incomeExpensesService.incomeBalance(customerIncomeDto);
        if (Objects.isNull(customerTradeRdto) || !customerTradeRdto.isSuccess()) {
            throw new HMYRuntimeException(506800019);
        }

        /*step3.客户到联系人转账*/
        List<Long> offsetedCustomerContactorIds = new ArrayList<>();
        List<CustomerContactorIAccountInfoJson> customerContactorAmountInfos = receiptOffsetBillDo.getAccountExtensionInfos().getCustomerContactorAmountInfo();
        if (CollectionUtil.isNotEmpty(customerContactorAmountInfos)) {
            customerContactorAmountInfos.forEach(r -> {
                TransferDto transferDto = new TransferDto();
                transferDto.setContactorId(r.getCustomerContactorId());
                transferDto.setCustomerId(receiptOffsetBillDo.getCustomerId());
                transferDto.setAmount(r.getApportionAmount());
                transferDto.setBusinessBillId(receiptOffsetBillId);
                transferDto.setBusinessType(AccountTradeBusinessTypeEnum.APPORTION);
                transferDto.setFeeIncurredTime(receiptOffsetBillDo.getReceiptedTime());
                Boolean transferBalanceResult = incomeExpensesService.transferBalance(transferDto);
                if (transferBalanceResult) {
                    offsetedCustomerContactorIds.add(r.getCustomerContactorId());
                }
            });
        }

        /*step4.手动核销*/
        doManualOffset(receiptOffsetBillDo, receiptContractApportionRecordDos, offsetedCustomerContactorIds);

        return Boolean.TRUE;
    }

    @Override
    public List<ReceiptedTypeEnumResponse> getReceiptedTypeEnums() {
        List<ReceiptedTypeEnumResponse> responses = new ArrayList<>();
        for (ReceiptedTypeEnum receiptedType : ReceiptedTypeEnum.values()) {
            ReceiptedTypeEnumResponse response = new ReceiptedTypeEnumResponse();
            response.setReceiptedType(receiptedType.getStatusCode());
            response.setReceiptedTypeDesc(receiptedType.getDisplayDesc());
            responses.add(response);
        }
        return responses;
    }

    @Transactional
    public void doManualOffset(ReceiptOffsetBillPo receiptOffsetBillDo, List<ReceiptContractApportionRecordPo> receiptContractApportionRecordDos, List<Long> offsetedCustomerContactorIds) {
        log.info("doManualOffset request:{}", JSON.toJSON(receiptOffsetBillDo));
        ManualOffsetDto manualOffsetDto = new ManualOffsetDto();
        manualOffsetDto.setCustomerId(receiptOffsetBillDo.getCustomerId());
        manualOffsetDto.setReceiptOffsetBillId(receiptOffsetBillDo.getReceiptOffsetBillId());
        manualOffsetDto.setSubmitUserId(receiptOffsetBillDo.getCreatorId());
        manualOffsetDto.setSubmitUserName(receiptOffsetBillDo.getCreatorName());
        List<ManualOffsetDto.ContractOffsetDetail> contractOffsetDetailList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(receiptContractApportionRecordDos)) {
            receiptContractApportionRecordDos = receiptContractApportionRecordDos.stream().filter(r -> offsetedCustomerContactorIds.contains(r.getCustomerContactorId())).collect(Collectors.toList());
            List<Long> updateIds = receiptContractApportionRecordDos.stream().map(ReceiptContractApportionRecordPo::getId).collect(Collectors.toList());
            receiptContractApportionRecordDos.forEach(r -> {
                ManualOffsetDto.ContractOffsetDetail contractOffsetDetail = new ManualOffsetDto.ContractOffsetDetail();
                contractOffsetDetail.setContactorId(r.getCustomerContactorId());
                contractOffsetDetail.setContractId(r.getContractId());
                contractOffsetDetail.setOffsetMaximumAmount(r.getActualOffsetAmount());
                contractOffsetDetail.setContractApportionRecordId(r.getId());
                contractOffsetDetailList.add(contractOffsetDetail);
            });

            manualOffsetDto.setContractOffsetDetailList(contractOffsetDetailList);
            ManualOffsetRdto manualOffset = offsetFeeBillService.manualOffset(manualOffsetDto);
            if (Objects.isNull(manualOffset) || !manualOffset.isSuccess()) {
                log.info("ReceiptOffsetBillService#doReceiptBillOffsetHandler.manualOffset response :{}", Objects.isNull(manualOffset) ? null : JSON.toJSON(manualOffset));
                throw new HMYRuntimeException(506800020);
            }
            receiptContractApportionRecordMapper.batchUpdateReceiptStatus(updateIds);
            log.info("ReceiptOffsetBillService#doReceiptBillOffsetHandler.manualOffset response :{}", JSON.toJSON(manualOffset));

        }
    }

    public ReceiptOffsetBillPo selectReceiptOffsetBillById(Long receiptOffsetBillId) {
        LambdaQueryWrapper<ReceiptOffsetBillPo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ReceiptOffsetBillPo::getReceiptOffsetBillId, receiptOffsetBillId);
        queryWrapper.eq(ReceiptOffsetBillPo::getIsDeleted, 0);
        return receiptOffsetBillMapper.selectOne(queryWrapper);
    }


    private void bossPageInfosQueryWrapperPackager(ReceiptOffsetBillBossPageQueryDto receiptOffsetBillBossPageQueryDto, ReceiptOffsetBillPageQueryPo receiptOffsetBillPageQueryPo) {
        if (Objects.nonNull(receiptOffsetBillBossPageQueryDto.getReceiptOffsetBillId())) {
            receiptOffsetBillPageQueryPo.setReceiptOffsetBillId(receiptOffsetBillBossPageQueryDto.getReceiptOffsetBillId());
        }
        if (Objects.nonNull(receiptOffsetBillBossPageQueryDto.getReceiptOffsetBillNo()) && StringUtils.isNotBlank(receiptOffsetBillBossPageQueryDto.getReceiptOffsetBillNo())) {
            receiptOffsetBillPageQueryPo.setReceiptOffsetBillNo(receiptOffsetBillBossPageQueryDto.getReceiptOffsetBillNo());
        }
        if (Objects.nonNull(receiptOffsetBillBossPageQueryDto.getCustomerId())) {
            receiptOffsetBillPageQueryPo.setCustomerId(receiptOffsetBillBossPageQueryDto.getCustomerId());
        }
        if (Objects.nonNull(receiptOffsetBillBossPageQueryDto.getCustomerContactorId())) {
            receiptOffsetBillPageQueryPo.setCustomerContactorId(receiptOffsetBillBossPageQueryDto.getCustomerContactorId());
        }
        if (Objects.nonNull(receiptOffsetBillBossPageQueryDto.getSaleManagerId())) {
            receiptOffsetBillPageQueryPo.setSaleManagerId(receiptOffsetBillBossPageQueryDto.getSaleManagerId());
        }

        if (CollectionUtil.isNotEmpty(receiptOffsetBillBossPageQueryDto.getReceiptOffsetBillStatus())) {
            receiptOffsetBillPageQueryPo.setBillStatusList(receiptOffsetBillBossPageQueryDto.getReceiptOffsetBillStatus());
        }

        if (Objects.nonNull(receiptOffsetBillBossPageQueryDto.getStartTime()) && Objects.nonNull(receiptOffsetBillBossPageQueryDto.getEndTime())) {
            receiptOffsetBillPageQueryPo.setCreateTimeStart(receiptOffsetBillBossPageQueryDto.getStartTime());
            receiptOffsetBillPageQueryPo.setCreateTimeEnd(receiptOffsetBillBossPageQueryDto.getEndTime());
        }
        if (Objects.nonNull(receiptOffsetBillBossPageQueryDto.getPageNum()) && Objects.isNull(receiptOffsetBillBossPageQueryDto.getPageSize())) {
            receiptOffsetBillPageQueryPo.setPageNum(receiptOffsetBillBossPageQueryDto.getPageNum());
            receiptOffsetBillPageQueryPo.setPageSize(receiptOffsetBillBossPageQueryDto.getPageSize());
        } else {
            receiptOffsetBillPageQueryPo.setPageNum(1);
            receiptOffsetBillPageQueryPo.setPageSize(10);
        }
    }

    public void setUserContextInfo(BaseDto baseDto) {
        ContextUserInfo userInfo = UserContextUtil.getCurrentUser();
        if (Objects.isNull(userInfo) || Objects.isNull(userInfo.getId()) || CollectionUtil.isEmpty(userInfo.getDeptIds())) {
            throw new HMYRuntimeException(506800003);
        }
        baseDto.setDeptIds(new ArrayList<>(userInfo.getDeptIds()));
        baseDto.setRoles(userInfo.getRoles());
        baseDto.setUpdaterId(userInfo.getId());
        baseDto.setUpdaterName(userInfo.getUserName());
        baseDto.setCreatorId(userInfo.getId());
        baseDto.setCreatorName(userInfo.getUserName());
    }

    /**
     * 创建流程引擎
     *
     * @param billCreateDto
     * @return
     */
    public StartProcessInstanceResponse createFlowProcess(ReceiptOffsetBillCreateDto billCreateDto) {
        StartProcessInstanceRequest startProcessInstanceRequest = new StartProcessInstanceRequest();
        startProcessInstanceRequest.setProcessDefinitionId(startProcessId);
        startProcessInstanceRequest.setUserId(billCreateDto.getUpdaterId());
        // 业务数据转map
        ReceiptOffsetBillProcessVariableDto variableDto = BeanUtil.copyProperties(billCreateDto, ReceiptOffsetBillProcessVariableDto.class);
        variableDto.buildReceiptOffsetBillStatus(ReceiptOffsetBillStatusEnum.AREA_MANAGER_APPROVE_ING);

        Map<String, Object> variables = BeanUtil.beanToMap(variableDto);
        //首次审批节点
        variables.put("approvalNode", ReceiptOffsetApprovalNodeEnum.AREA_MANAGER.getCode());
        startProcessInstanceRequest.setProcessVariables(variables);

        return flowProcessClientManager.start(startProcessInstanceRequest);
    }

    /**
     * 编辑重新提交审批流
     */
    public ApprovalTaskResponse editResubmitFlowProcess(ReceiptOffsetBillProcessVariableDto variableDto) {
        ApprovalTaskRequest approvalTaskRequest = new ApprovalTaskRequest();
        approvalTaskRequest.setTaskId(variableDto.getProcessCurrentTaskId());
        approvalTaskRequest.setComment("重新提交");
        approvalTaskRequest.setProcessInstanceId(variableDto.getProcessInstanceId());
        // 业务数据转map
//        ReceiptOffsetBillProcessVariableDto variableDto = BeanUtil.copyProperties(updateReceiptOffsetBillPo, ReceiptOffsetBillProcessVariableDto.class);
//        variableDto.setReceiptOffsetBillId(sourceReceiptOffsetBillPo.getReceiptOffsetBillId());
//        variableDto.setReceiptOffsetBillNo(sourceReceiptOffsetBillPo.getReceiptOffsetBillNo());
        variableDto.buildReceiptOffsetBillStatus(ReceiptOffsetBillStatusEnum.AREA_MANAGER_APPROVE_ING);

        Map<String, Object> variableMap = BeanUtil.beanToMap(variableDto);

        variableMap.put("approvalNode", ReceiptOffsetApprovalNodeEnum.AREA_MANAGER.getCode());
        variableMap.put("rejectCount", 0);
        variableMap.put("areaManagerAuditResult", null);
        variableMap.put("cashierAuditResult", null);
        variableMap.put("arAccountantAuditResult", null);
        approvalTaskRequest.setVariables(variableMap);

        return flowTaskClientManager.complete(approvalTaskRequest);
    }

    /**
     * 编辑后首次提交审批流
     */
    public StartProcessInstanceResponse editCreateFlowProcess(ReceiptOffsetBillProcessVariableDto variableDto) {
        StartProcessInstanceRequest startProcessInstanceRequest = new StartProcessInstanceRequest();
        startProcessInstanceRequest.setProcessDefinitionId(startProcessId);
        startProcessInstanceRequest.setUserId(variableDto.getUpdaterId());
        // 业务数据转map
//        ReceiptOffsetBillProcessVariableDto variableDto = BeanUtil.copyProperties(updateReceiptOffsetBillPo, ReceiptOffsetBillProcessVariableDto.class);
//        variableDto.setReceiptOffsetBillId(sourceReceiptOffsetBillPo.getReceiptOffsetBillId());
//        variableDto.setReceiptOffsetBillNo(sourceReceiptOffsetBillPo.getReceiptOffsetBillNo());
        variableDto.buildReceiptOffsetBillStatus(ReceiptOffsetBillStatusEnum.AREA_MANAGER_APPROVE_ING);

        Map<String, Object> variables = BeanUtil.beanToMap(variableDto);
        //首次审批节点
        variables.put("approvalNode", ReceiptOffsetApprovalNodeEnum.AREA_MANAGER.getCode());
        startProcessInstanceRequest.setProcessVariables(variables);

        return flowProcessClientManager.start(startProcessInstanceRequest);
    }

}




